<!DOCTYPE html>
<html lang="zh-CN" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>1.4 Dart语言简介 | 落光的Pro博客</title>
    <meta name="description" content="Vite & Vue powered static site generator.">
    <link rel="preload stylesheet" href="./assets/style.4b0df91d.css" as="style">
    
    <script type="module" src="./assets/app.0acbd3fd.js"></script>
    <link rel="preload" href="./assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="./assets/chunks/framework.eaf25f5b.js">
    <link rel="modulepreload" href="./assets/chunks/theme.ce44a0e6.js">
    <link rel="modulepreload" href="./assets/largeFrontEnd_flutter_chapter1_dart.md.6bba4e7c.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-1919c326><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0f60ec36></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0f60ec36> Skip to content </a><!--]--><!----><header class="VPNav" data-v-1919c326 data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-a0fd61f4><div class="container" data-v-a0fd61f4><div class="title" data-v-a0fd61f4><div class="VPNavBarTitle has-sidebar" data-v-a0fd61f4 data-v-86d1bed8><a class="title" href="./" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="./icon-radius.png" alt data-v-8426fc1a><!--]--><!--[-->落光的Pro博客<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-a0fd61f4><div class="curtain" data-v-a0fd61f4></div><div class="content-body" data-v-a0fd61f4><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-a0fd61f4><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-a0fd61f4 data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-9c007e85><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-9c007e85><span class="text" data-v-9c007e85><!----><span data-v-9c007e85>大前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-9c007e85><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-9c007e85><div class="VPMenu" data-v-9c007e85 data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/webFrontEnd/md/01.html" data-v-43f1e123><!--[-->Web前端<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/uniapp/" data-v-43f1e123><!--[-->Uni-app<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/weChatMiniProgram/" data-v-43f1e123><!--[-->微信小程序<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/electron/" data-v-43f1e123><!--[-->Electron<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/flutter/" data-v-43f1e123><!--[-->Flutter<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-e7ea1737 data-v-43f1e123><a class="VPLink link" href="./largeFrontEnd/interview/01.html" data-v-43f1e123><!--[-->前端面试题<!--]--></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./backEnd/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>后端</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./linux/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>Linux</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./myTeam/" tabindex="0" data-v-7f418b0f data-v-42ef59de><!--[--><span data-v-42ef59de>我的团队</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-a0fd61f4 data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-ce54a7d1 data-v-b1685198><span class="check" data-v-b1685198><span class="icon" data-v-b1685198><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-ce54a7d1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-ce54a7d1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-a0fd61f4 data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/luoguangguang" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="..." aria-label="cool link" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-a0fd61f4 data-v-40855f84 data-v-9c007e85><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-9c007e85><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-9c007e85><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-9c007e85><div class="VPMenu" data-v-9c007e85 data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-ce54a7d1 data-v-b1685198><span class="check" data-v-b1685198><span class="icon" data-v-b1685198><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-ce54a7d1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-ce54a7d1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://gitee.com/luoguangguang" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="..." aria-label="cool link" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Dribbble</title><path d="M12...6.38z"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-a0fd61f4 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-1919c326 data-v-79c8c1df><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-79c8c1df><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-79c8c1df><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-79c8c1df>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-79c8c1df data-v-1c15a60a><button data-v-1c15a60a>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-1919c326 data-v-b00e2fdd><div class="curtain" data-v-b00e2fdd></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-b00e2fdd><span class="visually-hidden" id="sidebar-aria-label" data-v-b00e2fdd> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-b00e2fdd><section class="VPSidebarItem level-0 collapsible" data-v-b00e2fdd data-v-e31bd47b><div class="item" role="button" tabindex="0" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><h2 class="text" data-v-e31bd47b>Flutter入门到实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-e31bd47b><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-e31bd47b><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-e31bd47b><!--[--><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter1/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第一章 初识Flutter</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter2/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第二章 简介</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter3/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第三章 基础组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter4/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第四章 布局类组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter5/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第五章 容器类Widget</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter6/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第六章 可滚动组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter7/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第七章 功能型Widget简介</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter8/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第八章 事件处理与通知</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter9/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第九章 动画</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter10/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十章 自定义组件</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter11/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十一章 文件操作</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter12/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十二章 Flutter 扩展</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter13/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十三章 多语言</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-e31bd47b data-v-e31bd47b><div class="item" data-v-e31bd47b><div class="indicator" data-v-e31bd47b></div><a class="VPLink link link" href="./largeFrontEnd/flutter/chapter14/index.html" data-v-e31bd47b><!--[--><p class="text" data-v-e31bd47b>第十四章 高级进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-1919c326 data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" role="navigation" data-v-3f215769 data-v-6ae8e080><div class="content" data-v-6ae8e080><div class="outline-marker" data-v-6ae8e080></div><div class="outline-title" role="heading" data-v-6ae8e080>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-6ae8e080><span class="visually-hidden" id="doc-outline-aria-label" data-v-6ae8e080> Table of Contents for current page </span><ul class="root" data-v-6ae8e080 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><div class="VPDocAsideCarbonAds" data-v-3f215769><div class="VPCarbonAds" data-v-2e1efd59></div></div><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _largeFrontEnd_flutter_chapter1_dart" data-v-6b87e69f><div><h1 id="_1-4-dart语言简介" tabindex="-1">1.4 Dart语言简介 <a class="header-anchor" href="#_1-4-dart语言简介" aria-label="Permalink to &quot;1.4 Dart语言简介&quot;">​</a></h1><p>在之前我们已经介绍过 Dart 语言的相关特性，读者可以翻看一下，如果读者已经熟悉 Dart 语法，可以跳过本节，如果你还不了解 Dart，也不用担心，按照笔者经验，如果你有过其他编程语言经验（尤其是 Java 或 JavaScript）的话会非常容易上手 Dart。当然，如果你是 iOS 开发者，也不用担心，Dart 中也有一些与 Swift 比较相似的特性，如命名参数等，笔者当时学习 Dart 时，也只是花了一个小时，看完 Dart 官网的 Language Tour，就开始动手写 Flutter 了，所以不用怕。</p><p>在笔者看来，Dart 在设计时应该是同时借鉴了 Java 和 JavaScript，同时又引入了一些现代编程语言的特性，如空安全，除此之外还有一些独创的语法，比如级联操作符。总之，熟悉之后，你会发现 Dart 是一门非常有意思的编程语言 ！</p><p>Dart 在静态语法方面和 Java 非常相似，如类型定义、函数声明、泛型等，而在动态特性方面又和 JavaScript 很像，如函数式特性、异步支持等。除了融合 Java 和 JavaScript 语言之所长之外，Dart 也具有一些其他很有表现力的语法，如可选命名参数、<code>..</code>（级联运算符）和<code>?.</code>（条件成员访问运算符）以及<code>??</code>（判空赋值运算符）。其实，对编程语言了解比较多的读者会发现，在 Dart 中其实看到的不仅有 Java 和 JavaScript 的影子，它还具有其他编程语言中的身影，如命名参数在 Objective-C 和 Swift 中早就很普遍，而<code>??</code>操作符在PHP 7.0 语法中就已经存在了，因此我们可以看到 Google 对 Dart 语言给予厚望，是想把 Dart 打造成一门集百家之所长的编程语言。</p><p>接下来，我们先对 Dart 语法做一个简单的介绍，然后再将 Dart 与 JavaScript 和 Java 做一个简要的对比，方便读者更好的理解。</p><blockquote><p>注意：由于本书并非专门介绍 Dart 语言的书籍，所以本章主要会介绍一下在 Flutter 开发中常用的语法特性，如果想更多了解 Dart，读者可以去 Dart 官网学习，现在互联网上 Dart 相关资料已经很多了。另外 Dart 2. 14 已经正式发布，所以本书所有示例均采用 Dart 2.14 语法。</p></blockquote><h2 id="_1-4-1-变量声明" tabindex="-1">1.4.1 变量声明 <a class="header-anchor" href="#_1-4-1-变量声明" aria-label="Permalink to &quot;1.4.1 变量声明&quot;">​</a></h2><h3 id="_1-var-关键字" tabindex="-1">1. <code>var</code> 关键字 <a class="header-anchor" href="#_1-var-关键字" aria-label="Permalink to &quot;1. `var` 关键字&quot;">​</a></h3><p>类似于 JavaScript 中的<code>var</code>，它可以接收任何类型的变量，但最大的不同是 Dart 中 var 变量一旦赋值，类型便会确定，则不能再改变其类型，如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> t </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hi world&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#6A737D;">// 下面代码在dart中会报错，因为变量t的类型已经确定为String，</span></span>
<span class="line"><span style="color:#6A737D;">// 类型一旦确定后则不能再更改其类型。</span></span>
<span class="line"><span style="color:#E1E4E8;">t </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1000</span><span style="color:#E1E4E8;">;</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">var</span><span style="color:#24292E;"> t </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hi world&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#6A737D;">// 下面代码在dart中会报错，因为变量t的类型已经确定为String，</span></span>
<span class="line"><span style="color:#6A737D;">// 类型一旦确定后则不能再更改其类型。</span></span>
<span class="line"><span style="color:#24292E;">t </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1000</span><span style="color:#24292E;">;</span></span></code></pre></div><p>上面的代码在 JavaScript 是没有问题的，前端开发者需要注意一下，之所以有此差异是因为 Dart 本身是一个强类型语言，任何变量都是有确定类型的，在 Dart 中，当用<code>var</code>声明一个变量后，Dart 在编译时会根据第一次赋值数据的类型来推断其类型，编译结束后其类型就已经被确定，而 JavaScript 是纯粹的弱类型脚本语言，var 只是变量的声明方式而已。</p><h3 id="_2-dynamic-和-object" tabindex="-1">2. <code>dynamic</code> 和 <code>Object</code> <a class="header-anchor" href="#_2-dynamic-和-object" aria-label="Permalink to &quot;2. `dynamic` 和 `Object`&quot;">​</a></h3><p><code>Object</code> 是 Dart 所有对象的根基类，也就是说在 Dart 中所有类型都是<code>Object</code>的子类(包括Function和Null)，所以任何类型的数据都可以赋值给<code>Object</code>声明的对象。 <code>dynamic</code>与<code>Object </code>声明的变量都可以赋值任意对象，且后期可以改变赋值的类型，这和 <code>var</code> 是不同的，如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">dynamic</span><span style="color:#E1E4E8;"> t;</span></span>
<span class="line"><span style="color:#79B8FF;">Object</span><span style="color:#E1E4E8;"> x;</span></span>
<span class="line"><span style="color:#E1E4E8;">t </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hi world&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">x </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&#39;Hello Object&#39;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#6A737D;">//下面代码没有问题</span></span>
<span class="line"><span style="color:#E1E4E8;">t </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1000</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">x </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1000</span><span style="color:#E1E4E8;">;</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">dynamic</span><span style="color:#24292E;"> t;</span></span>
<span class="line"><span style="color:#005CC5;">Object</span><span style="color:#24292E;"> x;</span></span>
<span class="line"><span style="color:#24292E;">t </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hi world&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">x </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;Hello Object&#39;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#6A737D;">//下面代码没有问题</span></span>
<span class="line"><span style="color:#24292E;">t </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1000</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">x </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1000</span><span style="color:#24292E;">;</span></span></code></pre></div><p><code>dynamic</code>与<code>Object</code>不同的是<code>dynamic</code>声明的对象编译器会提供所有可能的组合，而<code>Object</code>声明的对象只能使用 <code>Object</code> 的属性与方法, 否则编译器会报错，如:</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">dynamic</span><span style="color:#E1E4E8;"> a;</span></span>
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Object</span><span style="color:#E1E4E8;"> b </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">main</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">   a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">printLengths</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"><span style="color:#E1E4E8;"> }   </span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">printLengths</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">// 正常</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(a.length);</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">// 报错 The getter &#39;length&#39; is not defined for the class &#39;Object&#39;</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(b.length);</span></span>
<span class="line"><span style="color:#E1E4E8;"> }</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">dynamic</span><span style="color:#24292E;"> a;</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">Object</span><span style="color:#24292E;"> b </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">main</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">   a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">printLengths</span><span style="color:#24292E;">();</span></span>
<span class="line"><span style="color:#24292E;"> }   </span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">printLengths</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">// 正常</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(a.length);</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">// 报错 The getter &#39;length&#39; is not defined for the class &#39;Object&#39;</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(b.length);</span></span>
<span class="line"><span style="color:#24292E;"> }</span></span></code></pre></div><p><code>dynamic</code> 的这个特点使得我们在使用它时需要格外注意，这很容易引入一个运行时错误，比如下面代码在编译时不会报错，而在运行时会报错：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(a.xx); </span><span style="color:#6A737D;">// a是字符串，没有&quot;xx&quot;属性，编译时不会报错，运行时会报错</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(a.xx); </span><span style="color:#6A737D;">// a是字符串，没有&quot;xx&quot;属性，编译时不会报错，运行时会报错</span></span></code></pre></div><h3 id="_3-final和const" tabindex="-1">3. <code>final</code>和<code>const</code> <a class="header-anchor" href="#_3-final和const" aria-label="Permalink to &quot;3. `final`和`const`&quot;">​</a></h3><p>如果您从未打算更改一个变量，那么使用 <code>final</code> 或 <code>const</code>，不是<code>var</code>，也不是一个类型。 一个 <code>final</code> 变量只能被设置一次，两者区别在于：<code>const</code> 变量是一个编译时常量（编译时直接替换为常量值），<code>final</code>变量在第一次使用时被初始化。被<code>final</code>或者<code>const</code>修饰的变量，变量类型可以省略，如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">//可以省略String这个类型声明</span></span>
<span class="line"><span style="color:#F97583;">final</span><span style="color:#E1E4E8;"> str </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hi world&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#6A737D;">//final String str = &quot;hi world&quot;; </span></span>
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> str1 </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hi world&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#6A737D;">//const String str1 = &quot;hi world&quot;;</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">//可以省略String这个类型声明</span></span>
<span class="line"><span style="color:#D73A49;">final</span><span style="color:#24292E;"> str </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hi world&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#6A737D;">//final String str = &quot;hi world&quot;; </span></span>
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> str1 </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hi world&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#6A737D;">//const String str1 = &quot;hi world&quot;;</span></span></code></pre></div><h3 id="_4-空安全-null-safety" tabindex="-1">4. 空安全（null-safety） <a class="header-anchor" href="#_4-空安全-null-safety" aria-label="Permalink to &quot;4. 空安全（null-safety）&quot;">​</a></h3><p>Dart 中一切都是对象，这意味着如果我们定义一个数字，在初始化它之前如果我们使用了它，假如没有某种检查机制，则不会报错，比如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">test</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> i; </span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(i</span><span style="color:#F97583;">*</span><span style="color:#79B8FF;">8</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">test</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> i; </span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(i</span><span style="color:#D73A49;">*</span><span style="color:#005CC5;">8</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>在 Dart 引入空安全之前，上面代码在执行前不会报错，但会触发一个运行时错误，原因是 i 的值为 null 。但现在有了空安全，则定义变量时我们可以指定变量是可空还是不可空。</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> i </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">8</span><span style="color:#E1E4E8;">; </span><span style="color:#6A737D;">//默认为不可空，必须在定义时初始化。</span></span>
<span class="line"><span style="color:#79B8FF;">int</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> j; </span><span style="color:#6A737D;">// 定义为可空类型，对于可空变量，我们在使用前必须判空。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 如果我们预期变量不能为空，但在定义时不能确定其初始值，则可以加上late关键字，</span></span>
<span class="line"><span style="color:#6A737D;">// 表示会稍后初始化，但是在正式使用它之前必须得保证初始化过了，否则会报错</span></span>
<span class="line"><span style="color:#F97583;">late</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> k;</span></span>
<span class="line"><span style="color:#E1E4E8;">k</span><span style="color:#F97583;">=</span><span style="color:#79B8FF;">9</span><span style="color:#E1E4E8;">;</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">int</span><span style="color:#24292E;"> i </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">8</span><span style="color:#24292E;">; </span><span style="color:#6A737D;">//默认为不可空，必须在定义时初始化。</span></span>
<span class="line"><span style="color:#005CC5;">int</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> j; </span><span style="color:#6A737D;">// 定义为可空类型，对于可空变量，我们在使用前必须判空。</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">// 如果我们预期变量不能为空，但在定义时不能确定其初始值，则可以加上late关键字，</span></span>
<span class="line"><span style="color:#6A737D;">// 表示会稍后初始化，但是在正式使用它之前必须得保证初始化过了，否则会报错</span></span>
<span class="line"><span style="color:#D73A49;">late</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> k;</span></span>
<span class="line"><span style="color:#24292E;">k</span><span style="color:#D73A49;">=</span><span style="color:#005CC5;">9</span><span style="color:#24292E;">;</span></span></code></pre></div><p>如果一个变量我们定义为可空类型，在某些情况下即使我们给它赋值过了，但是预处理器仍然有可能识别不出，这时我们就要显式（通过在变量后面加一个”!“符号）告诉预处理器它已经不是null了，比如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Test</span><span style="color:#E1E4E8;">{</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">int</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> i;</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Function</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> fun;</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">(){</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">if</span><span style="color:#E1E4E8;">(i</span><span style="color:#F97583;">!=</span><span style="color:#79B8FF;">null</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(i</span><span style="color:#F97583;">!</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">*</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">8</span><span style="color:#E1E4E8;">); </span><span style="color:#6A737D;">//因为已经判过空，所以能走到这 i 必不为null，如果没有显式申明，则 IDE 会报错</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">if</span><span style="color:#E1E4E8;">(fun</span><span style="color:#F97583;">!=</span><span style="color:#79B8FF;">null</span><span style="color:#E1E4E8;">){</span></span>
<span class="line"><span style="color:#E1E4E8;">      </span><span style="color:#B392F0;">fun</span><span style="color:#E1E4E8;">!(); </span><span style="color:#6A737D;">// 同上</span></span>
<span class="line"><span style="color:#E1E4E8;">    }</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Test</span><span style="color:#24292E;">{</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">int</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> i;</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Function</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> fun;</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">say</span><span style="color:#24292E;">(){</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">if</span><span style="color:#24292E;">(i</span><span style="color:#D73A49;">!=</span><span style="color:#005CC5;">null</span><span style="color:#24292E;">) {</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(i</span><span style="color:#D73A49;">!</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">*</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">8</span><span style="color:#24292E;">); </span><span style="color:#6A737D;">//因为已经判过空，所以能走到这 i 必不为null，如果没有显式申明，则 IDE 会报错</span></span>
<span class="line"><span style="color:#24292E;">    }</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">if</span><span style="color:#24292E;">(fun</span><span style="color:#D73A49;">!=</span><span style="color:#005CC5;">null</span><span style="color:#24292E;">){</span></span>
<span class="line"><span style="color:#24292E;">      </span><span style="color:#6F42C1;">fun</span><span style="color:#24292E;">!(); </span><span style="color:#6A737D;">// 同上</span></span>
<span class="line"><span style="color:#24292E;">    }</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>上面中如果函数变量可空时，调用的时候可以用语法糖：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#E1E4E8;">fun</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">call</span><span style="color:#E1E4E8;">() </span><span style="color:#6A737D;">// fun 不为空时则会被调用</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292E;">fun</span><span style="color:#D73A49;">?</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">call</span><span style="color:#24292E;">() </span><span style="color:#6A737D;">// fun 不为空时则会被调用</span></span></code></pre></div><h2 id="_1-4-2-函数" tabindex="-1">1.4.2 函数 <a class="header-anchor" href="#_1-4-2-函数" aria-label="Permalink to &quot;1.4.2 函数&quot;">​</a></h2><p>Dart是一种真正的面向对象的语言，所以即使是函数也是对象，并且有一个类型<strong>Function</strong>。这意味着函数可以赋值给变量或作为参数传递给其他函数，这是函数式编程的典型特征。</p><h3 id="_1-函数声明" tabindex="-1">1. 函数声明 <a class="header-anchor" href="#_1-函数声明" aria-label="Permalink to &quot;1. 函数声明&quot;">​</a></h3><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">isNoble</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> atomicNumber) {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> _nobleGases[atomicNumber] </span><span style="color:#F97583;">!=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">null</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">isNoble</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> atomicNumber) {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> _nobleGases[atomicNumber] </span><span style="color:#D73A49;">!=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">null</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>Dart函数声明如果没有显式声明返回值类型时会默认当做<code>dynamic</code>处理，注意，函数返回值没有类型推断：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">typedef</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">CALLBACK</span><span style="color:#E1E4E8;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">//不指定返回类型，此时默认为dynamic，不是bool</span></span>
<span class="line"><span style="color:#B392F0;">isNoble</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> atomicNumber) {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> _nobleGases[atomicNumber] </span><span style="color:#F97583;">!=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">null</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">test</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">CALLBACK</span><span style="color:#E1E4E8;"> cb){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#B392F0;">cb</span><span style="color:#E1E4E8;">()); </span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"><span style="color:#6A737D;">//报错，isNoble不是bool类型</span></span>
<span class="line"><span style="color:#B392F0;">test</span><span style="color:#E1E4E8;">(isNoble);</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">typedef</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">CALLBACK</span><span style="color:#24292E;">();</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D;">//不指定返回类型，此时默认为dynamic，不是bool</span></span>
<span class="line"><span style="color:#6F42C1;">isNoble</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> atomicNumber) {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> _nobleGases[atomicNumber] </span><span style="color:#D73A49;">!=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">null</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">test</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">CALLBACK</span><span style="color:#24292E;"> cb){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">cb</span><span style="color:#24292E;">()); </span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"><span style="color:#6A737D;">//报错，isNoble不是bool类型</span></span>
<span class="line"><span style="color:#6F42C1;">test</span><span style="color:#24292E;">(isNoble);</span></span></code></pre></div><p>对于只包含一个表达式的函数，可以使用简写语法：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> isNoble (</span><span style="color:#79B8FF;">int</span><span style="color:#E1E4E8;"> atomicNumber)</span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span><span style="color:#E1E4E8;"> ;</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> isNoble (</span><span style="color:#005CC5;">int</span><span style="color:#24292E;"> atomicNumber)</span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span><span style="color:#24292E;"> ;</span></span></code></pre></div><h3 id="_2-函数作为变量" tabindex="-1">2. 函数作为变量 <a class="header-anchor" href="#_2-函数作为变量" aria-label="Permalink to &quot;2. 函数作为变量&quot;">​</a></h3><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> say </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> (str){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(str);</span></span>
<span class="line"><span style="color:#E1E4E8;">};</span></span>
<span class="line"><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;hi world&quot;</span><span style="color:#E1E4E8;">);</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">var</span><span style="color:#24292E;"> say </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> (str){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(str);</span></span>
<span class="line"><span style="color:#24292E;">};</span></span>
<span class="line"><span style="color:#6F42C1;">say</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;hi world&quot;</span><span style="color:#24292E;">);</span></span></code></pre></div><h3 id="_3-函数作为参数传递" tabindex="-1">3. 函数作为参数传递 <a class="header-anchor" href="#_3-函数作为参数传递" aria-label="Permalink to &quot;3. 函数作为参数传递&quot;">​</a></h3><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">//定义函数execute，它的参数类型为函数</span></span>
<span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">execute</span><span style="color:#E1E4E8;">(</span><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> callback) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">callback</span><span style="color:#E1E4E8;">(); </span><span style="color:#6A737D;">//执行传入的函数</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"><span style="color:#6A737D;">//调用execute，将箭头函数作为参数传递</span></span>
<span class="line"><span style="color:#B392F0;">execute</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=&gt;</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;xxx&quot;</span><span style="color:#E1E4E8;">))</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">//定义函数execute，它的参数类型为函数</span></span>
<span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">execute</span><span style="color:#24292E;">(</span><span style="color:#D73A49;">var</span><span style="color:#24292E;"> callback) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">callback</span><span style="color:#24292E;">(); </span><span style="color:#6A737D;">//执行传入的函数</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"><span style="color:#6A737D;">//调用execute，将箭头函数作为参数传递</span></span>
<span class="line"><span style="color:#6F42C1;">execute</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=&gt;</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;xxx&quot;</span><span style="color:#24292E;">))</span></span></code></pre></div><h4 id="_1-可选的位置参数" tabindex="-1">1）可选的位置参数 <a class="header-anchor" href="#_1-可选的位置参数" aria-label="Permalink to &quot;1）可选的位置参数&quot;">​</a></h4><p>包装一组函数参数，用[]标记为可选的位置参数，并放在参数列表的最后面：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> from, </span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> msg, [</span><span style="color:#79B8FF;">String</span><span style="color:#F97583;">?</span><span style="color:#E1E4E8;"> device]) {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">var</span><span style="color:#E1E4E8;"> result </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&#39;$</span><span style="color:#79B8FF;">from</span><span style="color:#9ECBFF;"> says $</span><span style="color:#79B8FF;">msg</span><span style="color:#9ECBFF;">&#39;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">if</span><span style="color:#E1E4E8;"> (device </span><span style="color:#F97583;">!=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">null</span><span style="color:#E1E4E8;">) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    result </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&#39;$</span><span style="color:#79B8FF;">result</span><span style="color:#9ECBFF;"> with a $</span><span style="color:#79B8FF;">device</span><span style="color:#9ECBFF;">&#39;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> result;</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">String</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">say</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> from, </span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> msg, [</span><span style="color:#005CC5;">String</span><span style="color:#D73A49;">?</span><span style="color:#24292E;"> device]) {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">var</span><span style="color:#24292E;"> result </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;$</span><span style="color:#005CC5;">from</span><span style="color:#032F62;"> says $</span><span style="color:#005CC5;">msg</span><span style="color:#032F62;">&#39;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">if</span><span style="color:#24292E;"> (device </span><span style="color:#D73A49;">!=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">null</span><span style="color:#24292E;">) {</span></span>
<span class="line"><span style="color:#24292E;">    result </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&#39;$</span><span style="color:#005CC5;">result</span><span style="color:#032F62;"> with a $</span><span style="color:#005CC5;">device</span><span style="color:#032F62;">&#39;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> result;</span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>下面是一个不带可选参数调用这个函数的例子：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;Bob&#39;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&#39;Howdy&#39;</span><span style="color:#E1E4E8;">); </span><span style="color:#6A737D;">//结果是： Bob says Howdy</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">say</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;Bob&#39;</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&#39;Howdy&#39;</span><span style="color:#24292E;">); </span><span style="color:#6A737D;">//结果是： Bob says Howdy</span></span></code></pre></div><p>下面是用第三个参数调用这个函数的例子：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;Bob&#39;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&#39;Howdy&#39;</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">&#39;smoke signal&#39;</span><span style="color:#E1E4E8;">); </span><span style="color:#6A737D;">//结果是：Bob says Howdy with a smoke signal</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">say</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;Bob&#39;</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&#39;Howdy&#39;</span><span style="color:#24292E;">, </span><span style="color:#032F62;">&#39;smoke signal&#39;</span><span style="color:#24292E;">); </span><span style="color:#6A737D;">//结果是：Bob says Howdy with a smoke signal</span></span></code></pre></div><h4 id="_2-可选的命名参数" tabindex="-1">2）可选的命名参数 <a class="header-anchor" href="#_2-可选的命名参数" aria-label="Permalink to &quot;2）可选的命名参数&quot;">​</a></h4><p>定义函数时，使用{param1, param2, …}，放在参数列表的最后面，用于指定命名参数。例如：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">//设置[bold]和[hidden]标志</span></span>
<span class="line"><span style="color:#F97583;">void</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">enableFlags</span><span style="color:#E1E4E8;">({</span><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> bold, </span><span style="color:#79B8FF;">bool</span><span style="color:#E1E4E8;"> hidden}) {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">// ... </span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">//设置[bold]和[hidden]标志</span></span>
<span class="line"><span style="color:#D73A49;">void</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">enableFlags</span><span style="color:#24292E;">({</span><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> bold, </span><span style="color:#005CC5;">bool</span><span style="color:#24292E;"> hidden}) {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">// ... </span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><p>调用函数时，可以使用指定命名参数。例如：<code>paramName: value</code></p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">enableFlags</span><span style="color:#E1E4E8;">(bold</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span><span style="color:#E1E4E8;">, hidden</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">false</span><span style="color:#E1E4E8;">);</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">enableFlags</span><span style="color:#24292E;">(bold</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span><span style="color:#24292E;">, hidden</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">false</span><span style="color:#24292E;">);</span></span></code></pre></div><p>可选命名参数在Flutter中使用非常多。<strong>注意，不能同时使用可选的位置参数和可选的命名参数</strong>。</p><h2 id="_1-4-3-mixin" tabindex="-1">1.4.3 mixin <a class="header-anchor" href="#_1-4-3-mixin" aria-label="Permalink to &quot;1.4.3 mixin&quot;">​</a></h2><p>Dart 是不支持多继承的，但是它支持 mixin，简单来讲 mixin 可以 “组合” 多个类，我们通过一个例子来理解。</p><p>定义一个 Person 类，实现吃饭、说话、走路和写代码功能，同时定义一个 Dog 类，实现吃饭、和走路功能：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Person</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">say</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;say&#39;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">mixin</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Eat</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">eat</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;eat&#39;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">mixin</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Walk</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">walk</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;walk&#39;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">mixin</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Code</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">code</span><span style="color:#E1E4E8;">() {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&#39;key&#39;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }</span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Dog</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">with</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Eat</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">Walk</span><span style="color:#E1E4E8;">{}</span></span>
<span class="line"><span style="color:#F97583;">class</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Man</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">extends</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Person</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">with</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">Eat</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">Walk</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">Code</span><span style="color:#E1E4E8;">{}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Person</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">say</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;say&#39;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">mixin</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Eat</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">eat</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;eat&#39;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">mixin</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Walk</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">walk</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;walk&#39;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">mixin</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Code</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">code</span><span style="color:#24292E;">() {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&#39;key&#39;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">  }</span></span>
<span class="line"><span style="color:#24292E;">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Dog</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">with</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Eat</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">Walk</span><span style="color:#24292E;">{}</span></span>
<span class="line"><span style="color:#D73A49;">class</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Man</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">extends</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Person</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">with</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">Eat</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">Walk</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">Code</span><span style="color:#24292E;">{}</span></span></code></pre></div><p>我们定义了几个 mixin，然后通过 with 关键字将它们组合成不同的类。有一点需要注意：如果多个mixin 中有同名方法，with 时，会默认使用最后面的 mixin 的，mixin 方法中可以通过 super 关键字调用之前 mixin 或类中的方法。我们这里只介绍 mixin 最基本的特性，关于 mixin 更详细的内容读者可以自行百度。</p><h2 id="_1-4-4-异步支持" tabindex="-1">1.4.4 异步支持 <a class="header-anchor" href="#_1-4-4-异步支持" aria-label="Permalink to &quot;1.4.4 异步支持&quot;">​</a></h2><p>Dart类库有非常多的返回<code>Future</code>或者<code>Stream</code>对象的函数。 这些函数被称为<strong>异步函数</strong>：它们只会在设置好一些耗时操作之后返回，比如像 IO操作。而不是等到这个操作完成。</p><p><code>async</code>和<code>await</code>关键词支持了异步编程，允许您写出和同步代码很像的异步代码。</p><h3 id="_1-future" tabindex="-1">1. <code>Future</code> <a class="header-anchor" href="#_1-future" aria-label="Permalink to &quot;1. `Future`&quot;">​</a></h3><p><code>Future</code>与JavaScript中的<code>Promise</code>非常相似，表示一个异步操作的最终完成（或失败）及其结果值的表示。简单来说，它就是用于处理异步操作的，异步处理成功了就执行成功的操作，异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果，要么成功，要么失败。</p><p>由于本身功能较多，这里我们只介绍其常用的API及特性。还有，请记住，<code>Future</code> 的所有API的返回值仍然是一个<code>Future</code>对象，所以可以很方便的进行链式调用。</p><h4 id="_1-future-then" tabindex="-1">1）<code>Future.then</code> <a class="header-anchor" href="#_1-future-then" aria-label="Permalink to &quot;1）`Future.then`&quot;">​</a></h4><p>为了方便示例，在本例中我们使用<code>Future.delayed</code> 创建了一个延时任务（实际场景会是一个真正的耗时任务，比如一次网络请求），即2秒后返回结果字符串&quot;hi world!&quot;，然后我们在<code>then</code>中接收异步结果并打印结果，代码如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">),(){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hi world!&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((data){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(data);</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">),(){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hi world!&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((data){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(data);</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><h4 id="_2-future-catcherror" tabindex="-1">2）<code>Future.catchError</code> <a class="header-anchor" href="#_2-future-catcherror" aria-label="Permalink to &quot;2）`Future.catchError`&quot;">​</a></h4><p>如果异步任务发生错误，我们可以在<code>catchError</code>中捕获错误，我们将上面示例改为：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">),(){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#F97583;">throw</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">AssertionError</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;Error&quot;</span><span style="color:#E1E4E8;">);  </span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((data){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//执行成功会走到这里  </span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;success&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">catchError</span><span style="color:#E1E4E8;">((e){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//执行失败会走到这里  </span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">),(){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#D73A49;">throw</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">AssertionError</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;Error&quot;</span><span style="color:#24292E;">);  </span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((data){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//执行成功会走到这里  </span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;success&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">catchError</span><span style="color:#24292E;">((e){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//执行失败会走到这里  </span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><p>在本示例中，我们在异步任务中抛出了一个异常，<code>then </code>的回调函数将不会被执行，取而代之的是 <code>catchError</code>回调函数将被调用；但是，并不是只有 <code>catchError</code>回调才能捕获错误，<code>then</code>方法还有一个可选参数<code>onError</code>，我们也可以用它来捕获异常：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">), () {</span></span>
<span class="line"><span style="color:#E1E4E8;">	</span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#E1E4E8;">	</span><span style="color:#F97583;">throw</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">AssertionError</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;Error&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((data) {</span></span>
<span class="line"><span style="color:#E1E4E8;">	</span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;success&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">}, onError</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (e) {</span></span>
<span class="line"><span style="color:#E1E4E8;">	</span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">), () {</span></span>
<span class="line"><span style="color:#24292E;">	</span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#24292E;">	</span><span style="color:#D73A49;">throw</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">AssertionError</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;Error&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((data) {</span></span>
<span class="line"><span style="color:#24292E;">	</span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;success&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">}, onError</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (e) {</span></span>
<span class="line"><span style="color:#24292E;">	</span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><h4 id="_3-future-whencomplete" tabindex="-1">3）<code>Future.whenComplete</code> <a class="header-anchor" href="#_3-future-whencomplete" aria-label="Permalink to &quot;3）`Future.whenComplete`&quot;">​</a></h4><p>有些时候，我们会遇到无论异步任务执行成功或失败都需要做一些事的场景，比如在网络请求前弹出加载对话框，在请求结束后关闭对话框。这种场景，有两种方法，第一种是分别在<code>then</code>或<code>catch</code>中关闭一下对话框，第二种就是使用<code>Future</code>的<code>whenComplete</code>回调，我们将上面示例改一下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">),(){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#F97583;">throw</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">AssertionError</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;Error&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((data){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//执行成功会走到这里 </span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(data);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">catchError</span><span style="color:#E1E4E8;">((e){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//执行失败会走到这里   </span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">whenComplete</span><span style="color:#E1E4E8;">((){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//无论成功或失败都会走到这里</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">),(){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//return &quot;hi world!&quot;;</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#D73A49;">throw</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">AssertionError</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;Error&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((data){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//执行成功会走到这里 </span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(data);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">catchError</span><span style="color:#24292E;">((e){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//执行失败会走到这里   </span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">whenComplete</span><span style="color:#24292E;">((){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//无论成功或失败都会走到这里</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><h4 id="_4-future-wait" tabindex="-1">4）<code>Future.wait</code> <a class="header-anchor" href="#_4-future-wait" aria-label="Permalink to &quot;4）`Future.wait`&quot;">​</a></h4><p>有些时候，我们需要等待多个异步任务都执行结束后才进行一些操作，比如我们有一个界面，需要先分别从两个网络接口获取数据，获取成功后，我们需要将两个接口数据进行特定的处理后再显示到UI界面上，应该怎么做？答案是<code>Future.wait</code>，它接受一个<code>Future</code>数组参数，只有数组中所有<code>Future</code>都执行成功后，才会触发<code>then</code>的成功回调，只要有一个<code>Future</code>执行失败，就会触发错误回调。下面，我们通过模拟<code>Future.delayed</code> 来模拟两个数据获取的异步任务，等两个异步任务都执行成功时，将两个异步任务的结果拼接打印出来，代码如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">wait</span><span style="color:#E1E4E8;">([</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 2秒后返回结果  </span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">), () {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hello&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }),</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 4秒后返回结果  </span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">4</span><span style="color:#E1E4E8;">), () {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot; world&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  })</span></span>
<span class="line"><span style="color:#E1E4E8;">]).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((results){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(results[</span><span style="color:#79B8FF;">0</span><span style="color:#E1E4E8;">]</span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;">results[</span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">]);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">catchError</span><span style="color:#E1E4E8;">((e){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">wait</span><span style="color:#24292E;">([</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 2秒后返回结果  </span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">), () {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hello&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  }),</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 4秒后返回结果  </span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">4</span><span style="color:#24292E;">), () {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot; world&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  })</span></span>
<span class="line"><span style="color:#24292E;">]).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((results){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(results[</span><span style="color:#005CC5;">0</span><span style="color:#24292E;">]</span><span style="color:#D73A49;">+</span><span style="color:#24292E;">results[</span><span style="color:#005CC5;">1</span><span style="color:#24292E;">]);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">catchError</span><span style="color:#24292E;">((e){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><p>执行上面代码，4秒后你会在控制台中看到“hello world”。</p><h3 id="_2-async-await" tabindex="-1">2. async/await <a class="header-anchor" href="#_2-async-await" aria-label="Permalink to &quot;2. async/await&quot;">​</a></h3><p>Dart中的<code>async/await</code> 和JavaScript中的<code>async/await</code>功能是一样的：异步任务串行化。如果你已经了解JavaScript中的<code>async/await</code>的用法，可以直接跳过本节。</p><h4 id="_1-回调地狱-callback-hell" tabindex="-1">1）回调地狱(Callback Hell) <a class="header-anchor" href="#_1-回调地狱-callback-hell" aria-label="Permalink to &quot;1）回调地狱(Callback Hell)&quot;">​</a></h4><p>如果代码中有大量异步逻辑，并且出现大量异步任务依赖其他异步任务的结果时，必然会出现<code>Future.then</code>回调中套回调情况。举个例子，比如现在有个需求场景是用户先登录，登录成功后会获得用户ID，然后通过用户ID，再去请求用户个人信息，获取到用户个人信息后，为了使用方便，我们需要将其缓存在本地文件系统，代码如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">//先分别定义各个异步任务</span></span>
<span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#B392F0;">login</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> userName, </span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> pwd){</span></span>
<span class="line"><span style="color:#E1E4E8;">	...</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//用户登录</span></span>
<span class="line"><span style="color:#E1E4E8;">};</span></span>
<span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">&lt;</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;">&gt; </span><span style="color:#B392F0;">getUserInfo</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> id){</span></span>
<span class="line"><span style="color:#E1E4E8;">	...</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//获取用户信息 </span></span>
<span class="line"><span style="color:#E1E4E8;">};</span></span>
<span class="line"><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">saveUserInfo</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> userInfo){</span></span>
<span class="line"><span style="color:#E1E4E8;">	...</span></span>
<span class="line"><span style="color:#E1E4E8;">	</span><span style="color:#6A737D;">// 保存用户信息 </span></span>
<span class="line"><span style="color:#E1E4E8;">};</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">//先分别定义各个异步任务</span></span>
<span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">String</span><span style="color:#24292E;">&gt; </span><span style="color:#6F42C1;">login</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> userName, </span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> pwd){</span></span>
<span class="line"><span style="color:#24292E;">	...</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//用户登录</span></span>
<span class="line"><span style="color:#24292E;">};</span></span>
<span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;">&lt;</span><span style="color:#005CC5;">String</span><span style="color:#24292E;">&gt; </span><span style="color:#6F42C1;">getUserInfo</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> id){</span></span>
<span class="line"><span style="color:#24292E;">	...</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//获取用户信息 </span></span>
<span class="line"><span style="color:#24292E;">};</span></span>
<span class="line"><span style="color:#005CC5;">Future</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">saveUserInfo</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> userInfo){</span></span>
<span class="line"><span style="color:#24292E;">	...</span></span>
<span class="line"><span style="color:#24292E;">	</span><span style="color:#6A737D;">// 保存用户信息 </span></span>
<span class="line"><span style="color:#24292E;">};</span></span></code></pre></div><p>接下来，执行整个任务流：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">login</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;alice&quot;</span><span style="color:#E1E4E8;">,</span><span style="color:#9ECBFF;">&quot;******&quot;</span><span style="color:#E1E4E8;">).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((id){</span></span>
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">//登录成功后通过，id获取用户信息    </span></span>
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">getUserInfo</span><span style="color:#E1E4E8;">(id).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((userInfo){</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//获取用户信息后保存 </span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">saveUserInfo</span><span style="color:#E1E4E8;">(userInfo).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((){</span></span>
<span class="line"><span style="color:#E1E4E8;">       </span><span style="color:#6A737D;">//保存用户信息，接下来执行其他操作</span></span>
<span class="line"><span style="color:#E1E4E8;">        ...</span></span>
<span class="line"><span style="color:#E1E4E8;">    });</span></span>
<span class="line"><span style="color:#E1E4E8;">  });</span></span>
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">login</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;alice&quot;</span><span style="color:#24292E;">,</span><span style="color:#032F62;">&quot;******&quot;</span><span style="color:#24292E;">).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((id){</span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6A737D;">//登录成功后通过，id获取用户信息    </span></span>
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">getUserInfo</span><span style="color:#24292E;">(id).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((userInfo){</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//获取用户信息后保存 </span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">saveUserInfo</span><span style="color:#24292E;">(userInfo).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((){</span></span>
<span class="line"><span style="color:#24292E;">       </span><span style="color:#6A737D;">//保存用户信息，接下来执行其他操作</span></span>
<span class="line"><span style="color:#24292E;">        ...</span></span>
<span class="line"><span style="color:#24292E;">    });</span></span>
<span class="line"><span style="color:#24292E;">  });</span></span>
<span class="line"><span style="color:#24292E;">})</span></span></code></pre></div><p>可以感受一下，如果业务逻辑中有大量异步依赖的情况，将会出现上面这种在回调里面套回调的情况，过多的嵌套会导致的代码可读性下降以及出错率提高，并且非常难维护，这个问题被形象的称为<strong>回调地狱（Callback Hell）</strong>。回调地狱问题在之前 JavaScript 中非常突出，也是 JavaScript 被吐槽最多的点，但随着 ECMAScript 标准发布后，这个问题得到了非常好的解决，而解决回调地狱的两大神器正是 ECMAScript6 引入了<code>Promise</code>，以及ECMAScript7 中引入的<code>async/await</code>。 而在 Dart 中几乎是完全平移了 JavaScript 中的这两者：<code>Future </code>相当于<code>Promise</code>，而<code>async/await</code>连名字都没改。接下来我们看看通过<code>Future</code>和<code>async/await</code>如何消除上面示例中的嵌套问题。</p><h4 id="_2-消除回调地狱" tabindex="-1">2）消除回调地狱 <a class="header-anchor" href="#_2-消除回调地狱" aria-label="Permalink to &quot;2）消除回调地狱&quot;">​</a></h4><p>消除回调地狱主要有两种方式：</p><p><strong>一、使用Future消除Callback Hell</strong></p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">login</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;alice&quot;</span><span style="color:#E1E4E8;">,</span><span style="color:#9ECBFF;">&quot;******&quot;</span><span style="color:#E1E4E8;">).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((id){</span></span>
<span class="line"><span style="color:#E1E4E8;">  	</span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">getUserInfo</span><span style="color:#E1E4E8;">(id);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((userInfo){</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">saveUserInfo</span><span style="color:#E1E4E8;">(userInfo);</span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">((e){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#6A737D;">//执行接下来的操作 </span></span>
<span class="line"><span style="color:#E1E4E8;">}).</span><span style="color:#B392F0;">catchError</span><span style="color:#E1E4E8;">((e){</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">//错误处理  </span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);</span></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">login</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;alice&quot;</span><span style="color:#24292E;">,</span><span style="color:#032F62;">&quot;******&quot;</span><span style="color:#24292E;">).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((id){</span></span>
<span class="line"><span style="color:#24292E;">  	</span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">getUserInfo</span><span style="color:#24292E;">(id);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((userInfo){</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">saveUserInfo</span><span style="color:#24292E;">(userInfo);</span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">((e){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6A737D;">//执行接下来的操作 </span></span>
<span class="line"><span style="color:#24292E;">}).</span><span style="color:#6F42C1;">catchError</span><span style="color:#24292E;">((e){</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">//错误处理  </span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);</span></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><p>正如上文所述， <em>“<code>Future</code> 的所有API的返回值仍然是一个<code>Future</code>对象，所以可以很方便的进行链式调用”</em> ，如果在then 中返回的是一个<code>Future</code>的话，该<code>future</code>会执行，执行结束后会触发后面的<code>then</code>回调，这样依次向下，就避免了层层嵌套。</p><p><strong>二、使用 async/await 消除 callback hell</strong></p><p>通过<code>Future</code>回调中再返回<code>Future</code>的方式虽然能避免层层嵌套，但是还是有一层回调，有没有一种方式能够让我们可以像写同步代码那样来执行异步任务而不使用回调的方式？答案是肯定的，这就要使用<code>async/await</code>了，下面我们先直接看代码，然后再解释，代码如下：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">task</span><span style="color:#E1E4E8;">() </span><span style="color:#F97583;">async</span><span style="color:#E1E4E8;"> {</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#F97583;">try</span><span style="color:#E1E4E8;">{</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> id </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">await</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">login</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;alice&quot;</span><span style="color:#E1E4E8;">,</span><span style="color:#9ECBFF;">&quot;******&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#79B8FF;">String</span><span style="color:#E1E4E8;"> userInfo </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">await</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">getUserInfo</span><span style="color:#E1E4E8;">(id);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">await</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">saveUserInfo</span><span style="color:#E1E4E8;">(userInfo);</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//执行接下来的操作   </span></span>
<span class="line"><span style="color:#E1E4E8;">   } </span><span style="color:#F97583;">catch</span><span style="color:#E1E4E8;">(e){</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#6A737D;">//错误处理   </span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e);   </span></span>
<span class="line"><span style="color:#E1E4E8;">   }  </span></span>
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">task</span><span style="color:#24292E;">() </span><span style="color:#D73A49;">async</span><span style="color:#24292E;"> {</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#D73A49;">try</span><span style="color:#24292E;">{</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> id </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">await</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">login</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;alice&quot;</span><span style="color:#24292E;">,</span><span style="color:#032F62;">&quot;******&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#005CC5;">String</span><span style="color:#24292E;"> userInfo </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">await</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">getUserInfo</span><span style="color:#24292E;">(id);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">await</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">saveUserInfo</span><span style="color:#24292E;">(userInfo);</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//执行接下来的操作   </span></span>
<span class="line"><span style="color:#24292E;">   } </span><span style="color:#D73A49;">catch</span><span style="color:#24292E;">(e){</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6A737D;">//错误处理   </span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e);   </span></span>
<span class="line"><span style="color:#24292E;">   }  </span></span>
<span class="line"><span style="color:#24292E;">}</span></span></code></pre></div><ul><li><p><code>async</code>用来表示函数是异步的，定义的函数会返回一个<code>Future</code>对象，可以使用 then 方法添加回调函数。</p></li><li><p><code>await</code> 后面是一个<code>Future</code>，表示等待该异步任务完成，异步完成后才会往下走；<code>await</code>必须出现在 <code>async</code> 函数内部。</p></li></ul><p>可以看到，我们通过<code>async/await</code>将一个异步流用同步的代码表示出来了。</p><blockquote><p>其实，无论是在 JavaScript 还是 Dart 中，<code>async/await</code> 都只是一个语法糖，编译器或解释器最终都会将其转化为一个 Promise（Future）的调用链。</p></blockquote><h2 id="_1-4-5-stream" tabindex="-1">1.4.5 Stream <a class="header-anchor" href="#_1-4-5-stream" aria-label="Permalink to &quot;1.4.5 Stream&quot;">​</a></h2><p><code>Stream</code> 也是用于接收异步事件数据，和 <code>Future</code> 不同的是，它可以接收多个异步操作的结果（成功或失败）。 也就是说，在执行异步任务时，可以通过多次触发成功或失败事件来传递结果数据或错误异常。 <code>Stream</code> 常用于会多次读取数据的异步任务场景，如网络内容下载、文件读写等。举个例子：</p><div class="language-dart vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">dart</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#79B8FF;">Stream</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">fromFutures</span><span style="color:#E1E4E8;">([</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 1秒后返回结果</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">), () {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hello 1&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  }),</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 抛出一个异常</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">),(){</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">throw</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">AssertionError</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">&quot;Error&quot;</span><span style="color:#E1E4E8;">);</span></span>
<span class="line"><span style="color:#E1E4E8;">  }),</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#6A737D;">// 3秒后返回结果</span></span>
<span class="line"><span style="color:#E1E4E8;">  </span><span style="color:#79B8FF;">Future</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">delayed</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">Duration</span><span style="color:#E1E4E8;">(seconds</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">3</span><span style="color:#E1E4E8;">), () {</span></span>
<span class="line"><span style="color:#E1E4E8;">    </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">&quot;hello 3&quot;</span><span style="color:#E1E4E8;">;</span></span>
<span class="line"><span style="color:#E1E4E8;">  })</span></span>
<span class="line"><span style="color:#E1E4E8;">]).</span><span style="color:#B392F0;">listen</span><span style="color:#E1E4E8;">((data){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(data);</span></span>
<span class="line"><span style="color:#E1E4E8;">}, onError</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (e){</span></span>
<span class="line"><span style="color:#E1E4E8;">   </span><span style="color:#B392F0;">print</span><span style="color:#E1E4E8;">(e.message);</span></span>
<span class="line"><span style="color:#E1E4E8;">},onDone</span><span style="color:#F97583;">:</span><span style="color:#E1E4E8;"> (){</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8;">});</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#005CC5;">Stream</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">fromFutures</span><span style="color:#24292E;">([</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 1秒后返回结果</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1</span><span style="color:#24292E;">), () {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hello 1&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  }),</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 抛出一个异常</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">),(){</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">throw</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">AssertionError</span><span style="color:#24292E;">(</span><span style="color:#032F62;">&quot;Error&quot;</span><span style="color:#24292E;">);</span></span>
<span class="line"><span style="color:#24292E;">  }),</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#6A737D;">// 3秒后返回结果</span></span>
<span class="line"><span style="color:#24292E;">  </span><span style="color:#005CC5;">Future</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">delayed</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">Duration</span><span style="color:#24292E;">(seconds</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">3</span><span style="color:#24292E;">), () {</span></span>
<span class="line"><span style="color:#24292E;">    </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">&quot;hello 3&quot;</span><span style="color:#24292E;">;</span></span>
<span class="line"><span style="color:#24292E;">  })</span></span>
<span class="line"><span style="color:#24292E;">]).</span><span style="color:#6F42C1;">listen</span><span style="color:#24292E;">((data){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(data);</span></span>
<span class="line"><span style="color:#24292E;">}, onError</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (e){</span></span>
<span class="line"><span style="color:#24292E;">   </span><span style="color:#6F42C1;">print</span><span style="color:#24292E;">(e.message);</span></span>
<span class="line"><span style="color:#24292E;">},onDone</span><span style="color:#D73A49;">:</span><span style="color:#24292E;"> (){</span></span>
<span class="line"></span>
<span class="line"><span style="color:#24292E;">});</span></span></code></pre></div><p>上面的代码依次会输出：</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#e1e4e8;">I/flutter (17666): hello 1</span></span>
<span class="line"><span style="color:#e1e4e8;">I/flutter (17666): Error</span></span>
<span class="line"><span style="color:#e1e4e8;">I/flutter (17666): hello 3</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292e;">I/flutter (17666): hello 1</span></span>
<span class="line"><span style="color:#24292e;">I/flutter (17666): Error</span></span>
<span class="line"><span style="color:#24292e;">I/flutter (17666): hello 3</span></span></code></pre></div><p>代码很简单，就不赘述了。</p><blockquote><p>思考题：既然 Stream 可以接收多次事件，那能不能用 Stream 来实现一个订阅者模式的事件总线？</p></blockquote><h2 id="_1-4-6-dart和java及javascript对比" tabindex="-1">1.4.6 Dart和Java及JavaScript对比 <a class="header-anchor" href="#_1-4-6-dart和java及javascript对比" aria-label="Permalink to &quot;1.4.6 Dart和Java及JavaScript对比&quot;">​</a></h2><p>通过上面介绍，相信你对 Dart 应该有了一个初步的印象，由于笔者平时也使用 Java 和 JavaScript，下面笔者根据自己的经验，结合 Java 和 JavaScript，谈一下自己的看法。</p><blockquote><p>之所以将 Dart 与 Java 和 JavaScript 对比，是因为，这两者分别是强类型语言和弱类型语言的典型代表，并且 Dart 语法中很多地方也都借鉴了 Java 和 JavaScript。</p></blockquote><h3 id="_1-dart-vs-java" tabindex="-1">1. Dart vs Java <a class="header-anchor" href="#_1-dart-vs-java" aria-label="Permalink to &quot;1. Dart vs Java&quot;">​</a></h3><p>客观的来讲，Dart 在语法层面确实比 Java 更有表现力；在 VM 层面，Dart VM 在内存回收和吞吐量都进行了反复的优化，但具体的性能对比，笔者没有找到相关测试数据，但在笔者看来，只要 Dart 语言能流行，VM 的性能就不用担心，毕竟 Google 在 Go、JavaScript（v8）、Dalvik（ Android 上的 Java VM ）上已经有了很多技术积淀。值得注意的是 Dart 在 Flutter 中已经可以将 GC（内存垃圾回收）做到 10ms 以内，所以 Dart 和 Java 相比，决胜因素并不会是在性能方面。而在语法层面，Dart 要比 Java 更有表现力，最重要的是 Dart 对函数式编程支持要远强于 Java（目前只停留在 Lambda 表达式），而 Dart 目前真正的不足是<strong>生态</strong>，但笔者相信，随着 Flutter 的逐渐火热，会回过头来反推 Dart 生态加速发展，对于 Dart 来说，现在需要的是时间。</p><h3 id="_2-dart-vs-javascript" tabindex="-1">2. Dart vs JavaScript <a class="header-anchor" href="#_2-dart-vs-javascript" aria-label="Permalink to &quot;2. Dart vs JavaScript&quot;">​</a></h3><p>JavaScript 的“弱类型”一直被诟病，所以 TypeScript （JavaScript语言的超集，语法兼容JavaScript，但添加了“类型”）才有市场。就笔者使用过的脚本语言中（笔者曾使用过 Python、PHP），JavaScript 无疑是<strong>动态化</strong>支持最好的脚本语言，比如在 JavaScript 中，可以给任何对象在任何时候动态扩展属性，对于精通 JavaScript 的高手来说，这无疑是一把利剑。但是，任何事物都有两面性，JavaScript 强大的动态化特性也是把双刃剑，你可经常听到另一个声音，认为 JavaScript 的这种动态性糟糕透了，太过灵活反而导致代码很难预期，无法限制不被期望的修改。毕竟有些人总是对自己或别人写的代码不放心，他们希望能够让代码变得可控，并期望有一套静态类型检查系统来帮助自己减少错误。正因如此，在 Flutter中，Dart 几乎放弃了脚本语言动态化的特性，如不支持反射、也不支持动态创建函数等。并且 Dart 从 2.0 开始强制开启了类型检查（Strong Mode），原先的检查模式（checked mode）和可选类型（optional type）将淡出，所以在类型安全这个层面来说，Dart 和 TypeScript、CoffeeScript 是差不多的，所以单从动态性来看，Dart 并不具备什么明显优势，但综合起来看，Dart 既能进行服务端脚本、App 开发、Web 开发，这就有优势了！</p><p>笔者在本书第一版的时候就表示过很看好 Dart 语言的将来，事实上，这几年，在 Github 上 Dart 语言开发的项目数量一直保持高速增长，所以 enjoy it !</p></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-ef5dee53><!--[--><!--]--><div class="edit-info" data-v-ef5dee53><div class="edit-link" data-v-ef5dee53><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://gitee.com/luoguangguang/note/tree/master/docs/largeFrontEnd/flutter/chapter1/dart.md" target="_blank" rel="noreferrer" data-v-ef5dee53><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" aria-label="edit icon" data-v-ef5dee53><path d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z"></path><path d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z"></path></svg> 在Gitee上参与编辑此页<!--]--></a></div><!----></div><nav class="prev-next" data-v-ef5dee53><div class="pager" data-v-ef5dee53><!----></div><div class="pager" data-v-ef5dee53><a class="pager-link next" href="./largeFrontEnd/flutter/chapter1/index.html" data-v-ef5dee53><span class="desc" data-v-ef5dee53>Next page</span><span class="title" data-v-ef5dee53>第一章 初识Flutter</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-1919c326 data-v-e03eb2e1><div class="container" data-v-e03eb2e1><p class="message" data-v-e03eb2e1>Released under the MIT License.</p><p class="copyright" data-v-e03eb2e1>Copyright © 2023-present LG of GZU</p></div></footer><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"backend_index.md\":\"0cb07c7c\",\"largefrontend_electron_index.md\":\"adab8e13\",\"largefrontend_flutter_chapter1_index.md\":\"5106cc23\",\"index.md\":\"20a66851\",\"largefrontend_flutter_chapter10_intro.md\":\"5756d1e8\",\"largefrontend_flutter_chapter10_index.md\":\"87e47f16\",\"largefrontend_flutter_chapter1_flutter_intro.md\":\"9ad5fc78\",\"largefrontend_flutter_chapter12_package_and_plugin.md\":\"c2f14cd7\",\"largefrontend_flutter_chapter12_flutter_web.md\":\"f4b6b743\",\"largefrontend_flutter_chapter10_combine.md\":\"333319d8\",\"largefrontend_flutter_chapter14_flutter_ui_system.md\":\"a1011f7b\",\"largefrontend_flutter_chapter11_index.md\":\"35dcdd7c\",\"largefrontend_flutter_chapter12_index.md\":\"890b799c\",\"largefrontend_flutter_chapter13_index.md\":\"6db9b579\",\"largefrontend_flutter_chapter14_index.md\":\"87f7da6b\",\"largefrontend_flutter_chapter1_mobile_development_intro.md\":\"40c15ac2\",\"largefrontend_flutter_chapter10_turn_box.md\":\"6a792fe1\",\"largefrontend_flutter_chapter3_index.md\":\"bc1d0de5\",\"largefrontend_flutter_chapter4_stack.md\":\"3f5c3186\",\"largefrontend_flutter_chapter1_install_flutter.md\":\"4543c368\",\"largefrontend_flutter_chapter14_paint.md\":\"8f7289b0\",\"largefrontend_flutter_chapter5_padding.md\":\"9fadce05\",\"largefrontend_flutter_chapter4_index.md\":\"f9b298f7\",\"largefrontend_flutter_chapter2_flutter_package_mgr.md\":\"4a3b7161\",\"largefrontend_flutter_chapter11_socket.md\":\"e8264e44\",\"largefrontend_flutter_chapter4_intro.md\":\"1341b5fd\",\"largefrontend_flutter_chapter14_update.md\":\"e4d2c2f0\",\"largefrontend_flutter_chapter5_index.md\":\"455baa0a\",\"largefrontend_flutter_chapter4_alignment.md\":\"a6596610\",\"largefrontend_flutter_chapter13_multi_languages_support.md\":\"c113238d\",\"largefrontend_flutter_chapter11_dio.md\":\"64f4e813\",\"largefrontend_flutter_chapter2_first_flutter_app.md\":\"b650181d\",\"largefrontend_flutter_chapter2_flutter_app_debug.md\":\"67a72433\",\"largefrontend_flutter_chapter2_state_manage.md\":\"9bb80d37\",\"largefrontend_flutter_chapter6_index.md\":\"5a321b81\",\"largefrontend_flutter_chapter5_material_scaffold.md\":\"8e6b896a\",\"largefrontend_flutter_chapter3_buttons.md\":\"ef950360\",\"largefrontend_flutter_chapter10_done_widget.md\":\"c3b44318\",\"largefrontend_flutter_chapter6_single_child_scrollview.md\":\"e3f75f3b\",\"largefrontend_flutter_chapter14_paint_flow.md\":\"d2f8102a\",\"largefrontend_flutter_chapter6_intro.md\":\"125a064e\",\"largefrontend_flutter_chapter5_transform.md\":\"22708e1e\",\"largefrontend_flutter_chapter14_layer.md\":\"4ed449fc\",\"largefrontend_flutter_chapter11_websocket.md\":\"0a022e47\",\"largefrontend_flutter_chapter5_fittedbox.md\":\"db915726\",\"largefrontend_flutter_chapter2_index.md\":\"d8e937b7\",\"largefrontend_flutter_chapter3_radio_and_checkbox.md\":\"025aba21\",\"largefrontend_flutter_chapter13_locallization_implement.md\":\"dc4b83fe\",\"largefrontend_flutter_chapter2_thread_model_and_error_report.md\":\"a29199d6\",\"largefrontend_flutter_chapter5_decoratedbox.md\":\"20f093ba\",\"largefrontend_flutter_chapter14_render_object.md\":\"55a1b551\",\"largefrontend_flutter_chapter14_element_buildcontext.md\":\"4272eae4\",\"largefrontend_flutter_chapter4_wrap_and_flow.md\":\"ac41b5bd\",\"largefrontend_flutter_chapter11_file_operation.md\":\"996a3a5d\",\"largefrontend_flutter_chapter13_faq.md\":\"ba7b9c70\",\"largefrontend_webfrontend_md_10.md\":\"51e0a312\",\"largefrontend_webfrontend_md_24.md\":\"0a4abd08\",\"largefrontend_flutter_chapter14_flutter_app_startup.md\":\"9b5942a1\",\"largefrontend_flutter_chapter10_custom_paint.md\":\"8b2a0a46\",\"largefrontend_flutter_chapter2_flutter_assets_mgr.md\":\"0e38b701\",\"largefrontend_interview_01.md\":\"2ac4b56d\",\"largefrontend_flutter_chapter8_index.md\":\"e83d3d80\",\"largefrontend_webfrontend_md_16.md\":\"a5610416\",\"largefrontend_flutter_chapter9_index.md\":\"3fb342a7\",\"largefrontend_flutter_chapter8_listener.md\":\"1b9b0316\",\"largefrontend_webfrontend_md_37.md\":\"3cacf3a2\",\"largefrontend_flutter_chapter4_layoutbuilder.md\":\"3d4bf94b\",\"largefrontend_webfrontend_md_17.md\":\"ee74edfb\",\"largefrontend_webfrontend_md_13.md\":\"b180bb5b\",\"largefrontend_flutter_chapter7_index.md\":\"0eb456b2\",\"largefrontend_webfrontend_md_31.md\":\"309453c7\",\"largefrontend_webfrontend_md_25.md\":\"95fdb4fe\",\"largefrontend_webfrontend_md_12.md\":\"3b14e491\",\"largefrontend_webfrontend_md_23.md\":\"18f08d72\",\"largefrontend_flutter_chapter11_json_model.md\":\"c84d2ccf\",\"largefrontend_webfrontend_md_01.md\":\"fbb7a35f\",\"largefrontend_flutter_chapter3_progress.md\":\"9bc148d3\",\"largefrontend_webfrontend_md_18.md\":\"ee651cc6\",\"largefrontend_flutter_sponsor.md\":\"e71431a9\",\"largefrontend_webfrontend_md_36.md\":\"f22f6d0d\",\"largefrontend_webfrontend_md_07.md\":\"71c2ad1d\",\"largefrontend_webfrontend_md_19.md\":\"e7907728\",\"largefrontend_webfrontend_md_20.md\":\"5a68bb4f\",\"largefrontend_webfrontend_md_32.md\":\"91d2f39f\",\"largefrontend_flutter_chapter7_futurebuilder_and_streambuilder.md\":\"af3535c0\",\"largefrontend_flutter_chapter9_hero.md\":\"25b46cf2\",\"largefrontend_flutter_chapter8_notification.md\":\"909f6756\",\"largefrontend_webfrontend_md_08.md\":\"0d59dce4\",\"largefrontend_flutter_chapter3_img_and_icon.md\":\"8b409b55\",\"largefrontend_webfrontend_md_04.md\":\"d6c15d55\",\"largefrontend_flutter_chapter9_animated_switcher.md\":\"9c0b3119\",\"largefrontend_webfrontend_md_22.md\":\"7d6fea68\",\"largefrontend_flutter_chapter2_flutter_widget_intro.md\":\"13414fea\",\"largefrontend_flutter_chapter13_intl.md\":\"d4776610\",\"largefrontend_overview_index.md\":\"3c87f69c\",\"largefrontend_flutter_chapter5_container.md\":\"373cc694\",\"largefrontend_wechatminiprogram_index.md\":\"7f40708d\",\"largefrontend_webfrontend_md_38.md\":\"3b6bb332\",\"linux_index.md\":\"624ecc66\",\"largefrontend_webfrontend_md_35.md\":\"f0538423\",\"myteam_index.md\":\"91a2c11f\",\"largefrontend_flutter_chapter6_pageview.md\":\"36fcbc65\",\"largefrontend_webfrontend_md_03.md\":\"2e5087f0\",\"largefrontend_webfrontend_md_21.md\":\"c181316e\",\"largefrontend_flutter_chapter3_input_and_form.md\":\"e4fba9dd\",\"largefrontend_flutter_chapter14_compositing.md\":\"6d96f932\",\"largefrontend_webfrontend_md_29.md\":\"c6fada7d\",\"largefrontend_flutter_chapter4_constraints.md\":\"9e4baace\",\"largefrontend_webfrontend_md_11.md\":\"63cd9c49\",\"largefrontend_webfrontend_md_14.md\":\"1423aeb1\",\"largefrontend_flutter_chapter6_tabview.md\":\"56048fb1\",\"largefrontend_webfrontend_md_33.md\":\"fdbe86fa\",\"largefrontend_flutter_chapter6_nestedscrollview.md\":\"2a66b86a\",\"largefrontend_webfrontend_md_34.md\":\"ad8ea220\",\"largefrontend_flutter_chapter2_flutter_router.md\":\"bb6e776c\",\"largefrontend_webfrontend_md_30.md\":\"cd2cb5aa\",\"largefrontend_flutter_chapter4_flex.md\":\"ebd43d6a\",\"largefrontend_webfrontend_md_09.md\":\"eedafcb1\",\"largefrontend_webfrontend_md_40.md\":\"4d4fefa1\",\"largefrontend_flutter_join_us.md\":\"44c81d86\",\"largefrontend_flutter_chapter9_route_transition.md\":\"f56cf837\",\"largefrontend_uniapp_index.md\":\"fa387c39\",\"largefrontend_flutter_chapter4_row_and_column.md\":\"964229f5\",\"largefrontend_flutter_chapter9_stagger_animation.md\":\"315538f5\",\"largefrontend_flutter_chapter3_text.md\":\"6720230c\",\"largefrontend_flutter_chapter10_watermark.md\":\"2e4ddf03\",\"largefrontend_flutter_chapter11_http.md\":\"efd2ee64\",\"largefrontend_webfrontend_md_06.md\":\"e20b049a\",\"largefrontend_flutter_summary.md\":\"2e31b0a8\",\"largefrontend_flutter_chapter6_animatedlist.md\":\"20d9436f\",\"largefrontend_flutter_chapter5_clip.md\":\"91f4174c\",\"largefrontend_webfrontend_md_02.md\":\"40cd2099\",\"largefrontend_flutter_chapter6_gridview.md\":\"b3be7e60\",\"largefrontend_flutter_chapter6_custom_scrollview.md\":\"01be950c\",\"largefrontend_flutter_chapter11_download_with_chunks.md\":\"9379cc89\",\"largefrontend_flutter_chapter6_scroll_controller.md\":\"ffa2d5fd\",\"largefrontend_flutter_chapter9_intro.md\":\"3fc29b5f\",\"largefrontend_flutter_chapter1_dart.md\":\"6bba4e7c\",\"largefrontend_flutter_chapter7_inherited_widget.md\":\"5a21d704\",\"largefrontend_flutter_index.md\":\"cd81fbbe\",\"largefrontend_flutter_reference.md\":\"36336375\",\"largefrontend_flutter_chapter6_keepalive.md\":\"535137be\",\"largefrontend_flutter_chapter14_layout.md\":\"0d7a8df3\",\"largefrontend_flutter_chapter6_sliver.md\":\"0c8b7553\",\"largefrontend_webfrontend_md_39.md\":\"aef49a57\",\"largefrontend_webfrontend_md_15.md\":\"bf9ff1a1\",\"largefrontend_flutter_chapter14_image_and_cache.md\":\"9622c56b\",\"largefrontend_webfrontend_md_28.md\":\"83169d10\",\"largefrontend_flutter_chapter8_eventbus.md\":\"fc0db86d\",\"largefrontend_flutter_chapter7_value_listenable_builder.md\":\"a0c76121\",\"largefrontend_flutter_preface.md\":\"604b9934\",\"largefrontend_flutter_chapter7_theme.md\":\"c21036bc\",\"largefrontend_webfrontend_md_05.md\":\"f7607009\",\"largefrontend_flutter_chapter6_listview.md\":\"472910bd\",\"largefrontend_flutter_chapter7_provider.md\":\"ab590744\",\"largefrontend_flutter_chapter8_gesture.md\":\"859bbb38\",\"largefrontend_flutter_chapter9_animated_widgets.md\":\"e8cd3c4d\",\"largefrontend_webfrontend_md_26.md\":\"4928006b\",\"largefrontend_flutter_chapter10_gradient_circular_progress_demo.md\":\"b3d48a2c\",\"largefrontend_flutter_chapter8_hittest.md\":\"e963812b\",\"largefrontend_flutter_chapter7_willpopscope.md\":\"d224ecce\",\"largefrontend_flutter_chapter9_animation_structure.md\":\"672eb3c0\",\"largefrontend_flutter_chapter8_gesture_conflict.md\":\"15bbadba\",\"largefrontend_webfrontend_md_27.md\":\"0b5b5e39\",\"largefrontend_flutter_chapter7_dailog.md\":\"5f91e51a\",\"largefrontend_flutter_chapter10_custom_checkbox.md\":\"0db7d50f\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"落光的Pro博客\",\"description\":\"Vite & Vue powered static site generator.\",\"base\":\"./\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"search\":{\"provider\":\"local\",\"options\":{\"locales\":{\"zh\":{\"translations\":{\"button\":{\"buttonText\":\"搜索文档\",\"buttonAriaLabel\":\"搜索文档\"},\"modal\":{\"noResultsText\":\"无法找到相关结果\",\"resetButtonTitle\":\"清除查询条件\",\"footer\":{\"selectText\":\"选择\",\"navigateText\":\"切换\"}}}}}}},\"logo\":\"/icon-radius.png\",\"nav\":[{\"text\":\"大前端\",\"items\":[{\"text\":\"Web前端\",\"link\":\"/largeFrontEnd/webFrontEnd/md/01.md\"},{\"text\":\"Uni-app\",\"link\":\"/largeFrontEnd/uniapp/\"},{\"text\":\"微信小程序\",\"link\":\"/largeFrontEnd/weChatMiniProgram/\"},{\"text\":\"Electron\",\"link\":\"/largeFrontEnd/electron/\"},{\"text\":\"Flutter\",\"link\":\"/largeFrontEnd/flutter/\"},{\"text\":\"前端面试题\",\"link\":\"/largeFrontEnd/interview/01.md\"}]},{\"text\":\"后端\",\"link\":\"/backEnd/\"},{\"text\":\"Linux\",\"link\":\"/linux/\"},{\"text\":\"我的团队\",\"link\":\"/myTeam/\"}],\"sidebar\":{\"/largeFrontEnd/webFrontEnd/\":[{\"text\":\"第一阶段  基础入门\",\"collapsed\":true,\"items\":[{\"text\":\"一、基础认知\",\"link\":\"/largeFrontEnd/webFrontEnd/md/01.md\"},{\"text\":\"二、HTML标签学习\",\"link\":\"/largeFrontEnd/webFrontEnd/md/02.md\"},{\"text\":\"三、HTML基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/03.md\"},{\"text\":\"四、CSS基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/04.md\"},{\"text\":\"五、CSS进阶\",\"link\":\"/largeFrontEnd/webFrontEnd/md/05.md\"},{\"text\":\"六、盒子模型\",\"link\":\"/largeFrontEnd/webFrontEnd/md/06.md\"},{\"text\":\"七、CSS浮动\",\"link\":\"/largeFrontEnd/webFrontEnd/md/07.md\"},{\"text\":\"八、CSS定位装饰\",\"link\":\"/largeFrontEnd/webFrontEnd/md/08.md\"},{\"text\":\"九、CSS精灵图\",\"link\":\"/largeFrontEnd/webFrontEnd/md/09.md\"},{\"text\":\"项目前置认知\",\"link\":\"/largeFrontEnd/webFrontEnd/md/10.md\"},{\"text\":\"项目结构搭建\",\"link\":\"/largeFrontEnd/webFrontEnd/md/11.md\"},{\"text\":\"字体图标、动画\",\"link\":\"/largeFrontEnd/webFrontEnd/md/12.md\"},{\"text\":\"移动web开发\",\"link\":\"/largeFrontEnd/webFrontEnd/md/13.md\"}]},{\"text\":\"第二阶段 技术进阶\",\"collapsed\":true,\"items\":[{\"text\":\"JavaScript深入浅出\",\"link\":\"/largeFrontEnd/webFrontEnd/md/14.md\"},{\"text\":\"JavaScript核心之web APIs\",\"link\":\"/largeFrontEnd/webFrontEnd/md/15.md\"},{\"text\":\"一、Web APIS导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/16.md\"},{\"text\":\"二、DOM导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/17.md\"},{\"text\":\"三、事件高级导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/18.md\"},{\"text\":\"四、BOM导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/19.md\"},{\"text\":\"五、PC网页特效导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/20.md\"},{\"text\":\"六、移动端特效导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/21.md\"},{\"text\":\"七、本地存储导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/22.md\"},{\"text\":\"jQuery入门导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/23.md\"},{\"text\":\"数据可视化项目导读\",\"link\":\"/largeFrontEnd/webFrontEnd/md/24.md\"}]},{\"text\":\"Node.js\",\"collapsed\":true,\"items\":[{\"text\":\"buffer(缓冲器)\",\"link\":\"/largeFrontEnd/webFrontEnd/md/25.md\"},{\"text\":\"计算机基础\",\"link\":\"/largeFrontEnd/webFrontEnd/md/26.md\"},{\"text\":\"fs模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/27.md\"},{\"text\":\"path模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/28.md\"},{\"text\":\"HTTP模块\",\"link\":\"/largeFrontEnd/webFrontEnd/md/29.md\"},{\"text\":\"Express框架\",\"link\":\"/largeFrontEnd/webFrontEnd/md/30.md\"},{\"text\":\"Mongodb\",\"link\":\"/largeFrontEnd/webFrontEnd/md/31.md\"}]},{\"text\":\"Ajax\",\"link\":\"/largeFrontEnd/webFrontEnd/md/32.md\"},{\"text\":\"前端面试题\",\"collapsed\":true,\"items\":[{\"text\":\"一、CSS\",\"link\":\"/largeFrontEnd/webFrontEnd/md/33.md\"},{\"text\":\"二、JavaScript\",\"link\":\"/largeFrontEnd/webFrontEnd/md/34.md\"},{\"text\":\"三、HTML5CSS3\",\"link\":\"/largeFrontEnd/webFrontEnd/md/35.md\"},{\"text\":\"四、Vue\",\"link\":\"/largeFrontEnd/webFrontEnd/md/36.md\"},{\"text\":\"五、Echarts\",\"link\":\"/largeFrontEnd/webFrontEnd/md/37.md\"},{\"text\":\"六.Uni-APP\",\"link\":\"/largeFrontEnd/webFrontEnd/md/38.md\"},{\"text\":\"七、webpack\",\"link\":\"/largeFrontEnd/webFrontEnd/md/39.md\"},{\"text\":\"八、Git\",\"link\":\"/largeFrontEnd/webFrontEnd/md/40.md\"}]}],\"/largeFrontEnd/flutter/\":[{\"text\":\"Flutter入门到实战\",\"collapsed\":false,\"items\":[{\"text\":\"第一章 初识Flutter\",\"link\":\"/largeFrontEnd/flutter/chapter1/index.md\"},{\"text\":\"第二章 简介\",\"link\":\"/largeFrontEnd/flutter/chapter2/index.md\"},{\"text\":\"第三章 基础组件\",\"link\":\"/largeFrontEnd/flutter/chapter3/index.md\"},{\"text\":\"第四章 布局类组件\",\"link\":\"/largeFrontEnd/flutter/chapter4/index.md\"},{\"text\":\"第五章 容器类Widget\",\"link\":\"/largeFrontEnd/flutter/chapter5/index.md\"},{\"text\":\"第六章 可滚动组件\",\"link\":\"/largeFrontEnd/flutter/chapter6/index.md\"},{\"text\":\"第七章 功能型Widget简介\",\"link\":\"/largeFrontEnd/flutter/chapter7/index.md\"},{\"text\":\"第八章 事件处理与通知\",\"link\":\"/largeFrontEnd/flutter/chapter8/index.md\"},{\"text\":\"第九章 动画\",\"link\":\"/largeFrontEnd/flutter/chapter9/index.md\"},{\"text\":\"第十章 自定义组件\",\"link\":\"/largeFrontEnd/flutter/chapter10/index.md\"},{\"text\":\"第十一章 文件操作\",\"link\":\"/largeFrontEnd/flutter/chapter11/index.md\"},{\"text\":\"第十二章 Flutter 扩展\",\"link\":\"/largeFrontEnd/flutter/chapter12/index.md\"},{\"text\":\"第十三章 多语言\",\"link\":\"/largeFrontEnd/flutter/chapter13/index.md\"},{\"text\":\"第十四章 高级进阶\",\"link\":\"/largeFrontEnd/flutter/chapter14/index.md\"}]}]},\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://gitee.com/luoguangguang\"},{\"icon\":{\"svg\":\"<svg role=\\\"img\\\" viewBox=\\\"0 0 24 24\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><title>Dribbble</title><path d=\\\"M12...6.38z\\\"/></svg>\"},\"link\":\"...\",\"ariaLabel\":\"cool link\"}],\"footer\":{\"message\":\"Released under the MIT License.\",\"copyright\":\"Copyright © 2023-present LG of GZU\"},\"editLink\":{\"pattern\":\"https://gitee.com/luoguangguang/note/tree/master/docs/:path\",\"text\":\"在Gitee上参与编辑此页\"},\"carbonAds\":{\"code\":\"your-carbon-code\",\"placement\":\"your-carbon-placement\"}},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>